#include <algorithm>
#include <cassert>
#include <iostream>
#include "rational.h"

rational::rational( int i )
:   n_(i),
    d_(1)
{
    
}


rational::rational( int n, int d )
:   n_(n),
    d_(d)
{
    assert (d!=0);
    normalize ();
}


rational::rational( const rational& r )
:   n_ (r.n_),
    d_ (r.d_)   
{

}

rational& rational::operator=( const rational& r )
{
    if (this != &r)
    {
        rational tmp (r);
        swap (tmp);
    }
    return *this;
}


void rational::swap( rational& r )
{
    std::swap(n_, r.n_);
    std::swap(d_, r.d_);
}


rational& rational::operator++()
{
    n_+=d_;
    return *this;
}

rational& rational::operator--()
{
    n_-=d_;
    return *this;
}

rational rational::operator++( int )
{
    rational tmp = *this;
    ++(*this);
    return tmp;
}

rational rational::operator--( int )
{
    rational tmp = *this;
    --(*this);
    return tmp;
}


rational& rational::operator+=( const rational& r )
{
    n_ = n_*r.d_ + d_*r.n_;
    d_ *= r.d_;
    normalize ();
    return *this;
}

rational& rational::operator-=( const rational& r )
{
    neg ();
    *this += r;
    neg ();
    return *this;
}


rational& rational::operator*=( const rational& r )
{
    n_*= r.n_;
    d_*= r.d_;
    normalize ();
    return *this;
}

rational& rational::operator/=( const rational& r )
{
    assert (r.n_ != 0);
    rev ();
    *this *= r;
    rev ();
    return *this;
}


rational& rational::neg()
{
    n_ = -n_;
    return *this;
}


rational& rational::rev()
{
    std::swap(n_, d_);
    return *this;
}

void rational::normalize()
{
    bool flag = (n_ > 0 && d_ < 0) || (n_< 0 && d_ > 0);
    int a = n_ = abs(n_), b = d_ = abs(d_);

    while(a!=0 && b!=0)
    {
        if(a >= b)
            a = a % b;
        else
            b = b % a;
        
    }

    n_ /= a+b;
    d_ /= a+b;
    if (flag)
        n_=-n_;
}


rational::operator double() const
{
    return (n_/static_cast<double>(d_));
}

void rational::print() const
{
    std::cout << "(" << n_ << "/" << d_ << ")\n";
}

rational operator+( const rational& a, const rational& b )
{
    rational res (a);
    return res+=b;
}

rational operator-( const rational& a, const rational& b )
{
    rational res (a);
    return res-=b;
}

rational operator*( const rational& a, const rational& b )
{
    rational res (a);
    return res*=b;
}

rational operator/( const rational& a, const rational& b )
{
    rational res (a);
    return res/=b;
}


bool operator==( const rational& a, const rational& b )
{
    return (a.n_ == b.n_ && a.d_ == b.d_);
}

bool operator!=( const rational& a, const rational& b )
{
    return !(a==b);
}

bool operator<( const rational& a, const rational& b )
{
    return (a.n_ * b.d_ < b.n_ * a.d_);
}


bool operator>( const rational& a, const rational& b )
{
    return (b < a);
}

bool operator<=( const rational& a, const rational& b )
{
    return !(b < a);
}

bool operator>=( const rational& a, const rational& b )
{
    return (b <= a);
}
